#include "HelloWorldScene.h"
#include "SimpleAudioEngine.h"
#include "GameOverScene.h"

using namespace cocos2d;
using namespace CocosDenshion;



CCScene* HelloWorld::scene()
{
    // 'scene' is an autorelease object
    CCScene *scene = CCScene::create();
    
    // 'layer' is an autorelease object
    HelloWorld *layer = HelloWorld::create();

    // add layer as a child to scene
    scene->addChild(layer);

    // return the scene
    return scene;
}

//解构函数，清理手工建立的导弹和敌人数组
HelloWorld::~HelloWorld()
{
    if (_targets)
    {
        _targets->release();
        _targets = NULL;
    }
    
    if (_projectiles){
        _projectiles->release();
        _projectiles = NULL;
    }
}

/*
HelloWorld::HelloWorld()
:_targets(NULL)
,_projectiles(NULL)
{
}
*/

// on "init" you need to initialize your instance
bool HelloWorld::init()
{
    // 为碰撞检测建立全局的敌人和子弹数组
    _targets = new CCArray;
    _projectiles = new CCArray;
    //过关计数器清零
    _projectilesDestroyed = 0;
    
    //////////////////////////////
    // 1. super init first. 带背景色初始化
    if ( !CCLayerColor::initWithColor(ccc4(255,255,255,255)) )
    {
        return false;
    }

    /////////////////////////////
    // 2. 加入关闭菜单项。menuCloseCallback负责处理该菜单动作。各种回调都是xxx_selector样式
    // 回调样式参考: cocos2dx\include\selector_protocol.h
    // 加入一个物体分三步。
    // 1. type *pointer = type::create(...)   建立对象
    // 2. pointer->setPosition  设置放置位置
    // 3. this->addChild 实际放置物体
    CCMenuItemImage *pCloseItem = CCMenuItemImage::create(
                                        "CloseNormal.png",
                                        "CloseSelected.png",
                                        this,
                                        menu_selector(HelloWorld::menuCloseCallback) );
    
    // 向导演获取窗口尺寸
    CCSize size = CCDirector::sharedDirector()->getWinSize();
    // 定位
    pCloseItem->setPosition( ccp(size.width - 20, 20) );

    // create menu, it's an autorelease object
    // 加入菜单分两步
    // 1. 建立menu item
    // 2. 建立menu (CCmenu)
    // 3. 最后总是 this->addChild将物体加入layer
    CCMenu* pMenu = CCMenu::create(pCloseItem, NULL);
    pMenu->setPosition( CCPointZero );
    this->addChild(pMenu, 1);
    this->setTouchEnabled(true);

    /////////////////////////////
    // 3. 以下加入您的代码
    // 加入仙女
    CCSprite* pSprite = CCSprite::create("Player.png");
    // 仙女在屏幕左端. 注意下面获取的是图像物体尺寸
    pSprite->setPosition( ccp(pSprite->getContentSize().width/2, size.height/2) );
    // 将仙女实际加入层
    this->addChild(pSprite, 0);
    
    //敌人入场
    this->schedule(schedule_selector(HelloWorld::gameLogic),.5); //0.5, 出场延迟
    //碰撞检测
    this->scheduleUpdate();
    
    SimpleAudioEngine::sharedEngine()->playBackgroundMusic("background-music-aac.wav", true);
    SimpleAudioEngine::sharedEngine()->preloadEffect("smashing.wav");
    SimpleAudioEngine::sharedEngine()->preloadEffect("pew-pew-lei.wav");
    return true;
}


//typedef void (CCObject::*SEL_SCHEDULE)(float);
void HelloWorld::gameLogic(float dt) //游戏逻辑:加入敌人
{
    this->addTarget();
}

//typedef void (CCObject::*SEL_MenuHandler)(CCObject*);
void HelloWorld::menuCloseCallback(CCObject* pnt)
{
    CCDirector::sharedDirector()->end();

#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
    exit(0);
#endif
}

//CCNode传进来当前的物体对象。removeChild从层上移除这个对象。
void HelloWorld::spriteMoveFinished(CCNode *sender)
{
    //如果有一个指针p, 我们需要把它的类型和所指向的类型改为TYEP *TYPE, 那么语法格式是: (TYPE *)p；
    CCSprite *sprite = (CCSprite *)sender;
    this->removeChild(sprite, true);
    
    //清理数组
    if (sprite->getTag() == 1)  // target
    {
        _targets->removeObject(sprite);
    }
    else if (sprite->getTag() == 2) // projectile
    {
        _projectiles->removeObject(sprite);
    }
}

void HelloWorld::ccTouchesEnded(CCSet* touches, CCEvent* event)
{
    SimpleAudioEngine::sharedEngine()->playEffect("pew-pew-lei.wav");
    // 触摸点位置
    CCTouch *touch = (CCTouch*)(touches->anyObject());
    CCPoint location = touch->locationInView();
    location = CCDirector::sharedDirector()->convertToGL(location);
    
    // 建立导弹初始位置
    CCSize winSize = CCDirector::sharedDirector()->getWinSize();
    CCSprite *projectile = CCSprite::create("Projectile.png");
    
    //加入导弹数组。（为碰撞监测做准备)
    // tag"2" 为导弹
    projectile->setTag(2);
    _projectiles->addObject(projectile);
    
    //在导弹的初始位置. 仙女的x轴宽度，窗口的一半高度开始画
    projectile->setPosition(ccp(20,winSize.height/2));
    
    // 确定触摸点与导弹的偏移位置: 触摸点坐标减去导弹坐标。
    // 这两个值用来计算斜率。
    // 斜率又用来从x推导y的目标点
    int offX = location.x - projectile->getPosition().x;
    int offY = location.y - projectile->getPosition().y;
    
    //Bail out if we are shooting down or backwards
    if (offX<=0) return;
    
    // Ok to add now - we've double checked position
    this->addChild(projectile);
    
    //Determine where we wish to shoot the projectile to
    
    // 计算目标坐标。
    // x点: 窗口宽度加上导弹宽度的一半
    int realX = winSize.width + (projectile->getContentSize().width/2);
    // 斜率
    float ratio = (float)offY / (float)offX;
    // y点: 当前导弹y轴坐标, 加上x轴乘以斜率. 就是目标y坐标
    int realY = (realX * ratio) + projectile->getPosition().y;
    CCPoint realDest = ccp(realX, realY);
    
    //计算最终射击长度. offRealX和offRealY都是临时变量. 该长度将用来计算线性速度
    int offRealX = realX - projectile->getPosition().x;
    int offRealY = realY - projectile->getPosition().y;
    float length = sqrtf((offRealX * offRealX)+(offRealY*offRealY));
    
    float velocity = 480/1; //480 pixels / 1 sec
    //模拟子弹的线性速度
    float realMoveDuration = length /velocity; 
    
    // Move projectile to actual endpoint
    projectile->runAction(CCSequence::actions(CCMoveTo::actionWithDuration(realMoveDuration, realDest),
                                              CCCallFuncN::actionWithTarget(this,
                                                                            callfuncN_selector(HelloWorld::spriteMoveFinished)
                                                                            )
                                                                            ,NULL
                                              )
                         );
}

//加入敌人移动
void HelloWorld::addTarget()
{
    CCSprite *target = CCSprite::create("Target.png"); //敌人图片
    
    //加入敌人到敌人数组
    //tag“1”为敌人
    target->setTag(1);
    _targets->addObject(target);
    
    CCSize winSize = CCDirector::sharedDirector()->getWinSize(); //窗口尺寸
    int minY = target->getContentSize().height/2;  //敌人图片高度的一半。 y轴最小位置
    int maxY = winSize.height-minY; // 窗口高度减去敌人图片高度一半， y轴最大值
    
    int rangeY = maxY - minY; //最大减最小。y轴移动范围
    int actualY = (rand() % rangeY) + minY; //实际y值。 y最小值加一个y轴范围随机数。算出敌人随机出现的y轴位置
    
    target->setPosition(ccp(winSize.width + (target->getContentSize().width/2),actualY));
    this->addChild(target);
    
    //duration控制物体经过时间。也就是速度。这里也是通过随机数来表现不同的入侵速度。
    int minDuration = (int)4.0;
    int maxDuration = (int)6.0;
    int rangeDuration = maxDuration - minDuration;
    int actualDuration = (rand() % rangeDuration)+minDuration;
    
    //移动物体: actionMove, actioMoveDone 移动和移动完成。注意移动完成是带回调处理的，所以用actionWithTarget
    //用runAction(CCFiniteTimeAction, CCFiniteTimeAction)来实际移动
    
    //x轴右往左移动。 y轴不变
    CCFiniteTimeAction *actionMove = CCMoveTo::actionWithDuration(actualDuration,
                                                                ccp(0-target->getContentSize().width/2, actualY));
    //typedef void (CCObject::*SEL_CallFuncN)(CCNode*);
    CCFiniteTimeAction *actionMoveDone = CCCallFuncN::actionWithTarget(this,
                                                                callfuncN_selector(HelloWorld::spriteMoveFinished));
    
    target->runAction(CCSequence::actions(actionMove, actionMoveDone, NULL));
    
}

// 碰撞监测及移除
void HelloWorld::update(float dt)
{
    //新建待清除子弹数组(临时)
    CCArray *projectilesToDelete = new CCArray;
    CCObject *it, *jt;
    //遍历子弹数组, 
    CCARRAY_FOREACH(_projectiles, it){
        CCSprite *projectile = (CCSprite*)it;
        // 得到子弹的区域。
        CCRect projectileRect = CCRectMake(
                                projectile->getPosition().x - (projectile->getContentSize().width/2),
                                projectile->getPosition().y - (projectile->getContentSize().height/2),
                                projectile->getContentSize().width,
                                projectile->getContentSize().height
                                );
        //新建待清除敌人数组(临时)
        CCArray *targetsToDelete = new CCArray;
        //遍历敌人数组
        CCARRAY_FOREACH(_targets, jt) {
            CCSprite *target = (CCSprite*)jt;
            //得到敌人区域
            CCRect targetRect = CCRectMake(
                                target->getPosition().x - (target->getContentSize().width/2),
                                target->getPosition().y - (target->getContentSize().height/2),
                                target->getContentSize().width,
                                target->getContentSize().height
                                );
            //子弹区域和敌人区域有重合, 则将敌人放入待清除敌人数组。
            //一颗子弹与多个敌人重合就会有多个待清除敌人。
            if (CCRect::CCRectIntersectsRect(projectileRect,targetRect))
            {
                targetsToDelete->addObject(target);
                SimpleAudioEngine::sharedEngine()->playEffect("smashing.wav");
            }
        } //敌人数组遍历结束
        
        //清除敌人:遍历待删除敌人数组。 从敌人数组删除相应的敌人。屏幕上移除敌人物体
        //注意这里并没有从待清除敌人数组删除元素。
        CCARRAY_FOREACH(targetsToDelete, jt){
           CCSprite *target = (CCSprite*)jt;
           _targets->removeObject(target);
           this->removeChild(target, true);
            //过关处理
            _projectilesDestroyed++;
            if (_projectilesDestroyed>30)
            {
                GameOverScene *gameOverScene = GameOverScene::node();
                gameOverScene->get_Layer()->getLabel()->setString("You Win!");
                CCDirector::sharedDirector()->replaceScene(gameOverScene);
            }
            
        }
        //如果待清除敌人数组有元素则表示有命中, 将子弹放入待清除子弹数组。
        if (targetsToDelete->count()>0)
        {
           projectilesToDelete->addObject(projectile);
        }
        // 释放待清除敌人数组
        targetsToDelete->release();
    } // 子弹数组遍历结束
    
    //清除子弹: 遍历待删除子弹数组. 从子弹数组删除相应的子弹。屏幕上移除子弹物体
    CCARRAY_FOREACH(projectilesToDelete, it){
        CCSprite *projectile = (CCSprite*)it;
        _projectiles->removeObject(projectile);
        this->removeChild(projectile,true);
    }
    // 释放待清除子弹数组
    projectilesToDelete->release();
}

